/* 
 *  Copyright (C) 2007 Dip. Ing. dell'Informazione, University of Pisa, Italy
 *  http://info.iet.unipi.it/~cng/ns2mesh80216/
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, USA
 */

#include "mesh_mac.h"
#include "w_mesh_defs.h"
#include "mesh_packet.h"
#include "mesh_phy.h"
#include "mesh_channel.h"
#include "w_mesh_buffers.h"
#include "mesh_buffers.h"
//#include <mesh_topology.h>
//#include "mesh_forwarding.h"
#include "mesh_bwmanager.h"
#include "mesh_bwmanager_frr.h"
#include "mesh_coordinator.h"
#include "mesh_coordinator_std.h"
#include "mesh_scheduler.h"
#include "mesh_scheduler_frr.h"

#include <ll.h>
#include <packet.h>
#include <ip.h>
#include <stat.h>

#include <iostream>


////////////////////////////////////new add/////////////////////////////////////////
int hdr_meshmac::offset_;

static class MeshmacHeaderClass:public PacketHeaderClass {

public:
	MeshmacHeaderClass() : PacketHeaderClass("PacketHeader/Meshmac",
	sizeof(hdr_meshmac)) {
		bind_offset(&hdr_meshmac::offset_);
	}
} class_hdrmeshmac ;



////////////////////////////////////////////////////////////////////////
/*
 *
 * class MeshMacMib
 *
 */

static class MeshMacMibClass : public TclClass {
public:
   MeshMacMibClass() : TclClass("MeshMacMib") {}
   TclObject* create(int, const char*const*) {
      return (new MeshMacMib());
   }
} class_mesh_mac_mib;

int
MeshMacMib::command (int argc, const char*const* argv)
{
	if ( argc == 3 && strcmp(argv[1], "phymib") == 0 ) {
		phyMib_ = (MeshPhyMib*) TclObject::lookup(argv[2]);
		timer_.start (phyMib_->frameDuration() - .000001);
		return TCL_OK;
	} else if ( argc == 3 && strcmp(argv[1], "allocation") == 0 ) {
		if ( strcmp (argv[2], "basic") == 0 ) {
			MeshMshDsch::allocationType() = MeshMshDsch::BASIC;
		} else if ( strcmp (argv[2], "contiguous") == 0 ) {
			MeshMshDsch::allocationType() = MeshMshDsch::CONTIGUOUS;
		} else {
			fprintf (stderr, "invalid MSH-DSCH allocation type '%s' "
					"Please choose 'basic' or 'contiguous'\n", argv[2]);
			return TCL_ERROR;
		}
		return TCL_OK;
	} else if ( argc == 4 && strcmp(argv[1], "crc") == 0 ) {
		int fid = atoi (argv[2]);
		if ( fid < 0 ) {
			fprintf (stderr, "invalid flow ID '%d'\n", fid);
			return TCL_ERROR;
		}
		if ( strcmp (argv[3], "crc") == 0 ) {
			flow2crc_[fid] = true;
		} else if ( strcmp (argv[2], "nocrc") == 0 ) {
			flow2crc_[fid] = false;
		} else {
			fprintf (stderr, "invalid command '%s' on flow ID %d. "
					"Please choose 'crc' or 'nocrc'\n", argv[3], fid);
			return TCL_ERROR;
		}
		return TCL_OK;
	} else if ( argc == 4 && strcmp(argv[1], "priority") == 0 ) {
	// 在tcl中设置流的优先级，好！
		unsigned int fid = atoi (argv[2]);
		unsigned int prio = atoi (argv[3]);
		if (  atoi (argv[2]) < 0 ) {
			fprintf (stderr, "invalid flow ID '%d'\n",  atoi (argv[2]));
			return TCL_ERROR;
		}
		if ( prio <= W_MeshMeshCid::MAX_PRIO ) {
			flow2prio_[fid] = prio;
		} else {
			fprintf (stderr, "invalid priority value'%d' on flow ID %d. "
					"Please choose a number between 0 and '%d''\n", prio, fid,
					W_MeshMeshCid::MAX_PRIO);
			return TCL_ERROR;
		}
		return TCL_OK;
	} else if ( argc == 4 && strcmp(argv[1], "precedence") == 0 ) {
		unsigned int fid = atoi (argv[2]);
		unsigned int prec = atoi (argv[3]);
		if ( atoi (argv[2]) < 0 ) {
			fprintf (stderr, "invalid flow ID '%d'\n", atoi (argv[2]));
			return TCL_ERROR;
		}
		if ( prec <= W_MeshMeshCid::MAX_PREC ) {
			flow2drop_[fid] = prec;
		} else {
			fprintf (stderr, "invalid precedence value'%d' on flow ID %d. "
					"Please choose a number between 0 and '%d''\n", prec, fid,
					W_MeshMeshCid::MAX_PREC);
			return TCL_ERROR;
		}
		return TCL_OK;
	}

	return TCL_ERROR;
}

void
MeshMacMib::handle ()
{
	++frame_;

	if ( W_MeshDebug::trace("WMMB::nextFrame") ) fprintf (stderr,
			"%.9f WMMB::nextFrame  %d\n", NOW, frame_);
	timer_.start (phyMib_->frameDuration());
}

w_mesh::BurstProfile
MeshMacMib::getBurstProfile ( W_MeshNodeId src, W_MeshNodeId dst )
{
	// assume that the value is present
	//std::list< Link >::iterator it;
	std::map< W_MeshNodeId , Link >::iterator it;
	for ( it = linkList_.begin(); it != linkList_.end(); ++it ){
		if ( ( it->second.src_ == src ) && ( it->second.dst_ == dst )  ) break;
	}
	return it->second.profile_;
}

void 
MeshMacMib::updateBurstProfile(W_MeshNodeId src, 
								W_MeshNodeId dst, w_mesh::BurstProfile p)
{
	//std::list< Link >::iterator it;
	std::map< W_MeshNodeId , Link >::iterator it;
	for ( it = linkList_.begin(); it != linkList_.end(); ++it ){
		if ( ( it->second.src_ == src ) && ( it->second.dst_ == dst )  ) {
			it->second.profile_ = p;
			return;
		}
	}	
	// if not present, insert
	linkList_[dst] = Link( src, dst, p ) ;
}

void 
MeshMacMib::deleteBurstProfile(W_MeshNodeId src, W_MeshNodeId dst)
{
	//std::list< Link >::iterator it;
	std::map< W_MeshNodeId , Link >::iterator it;
	for ( it = linkList_.begin(); it != linkList_.end(); ++it ){
		if ( ( it->second.src_ == src ) && ( it->second.dst_ == dst )  ) {
			linkList_.erase(it);
			return;
		}
	}	
//	printf( "没有相应的link , mac.cc:194\n " );
	//abort();
}


MeshMacMib::MeshMacMib ():timer_(this), phyMib_(0), frame_ (0)  {
	
	MeshMshDsch::allocationType() = MeshMshDsch::CONTIGUOUS; // 参考tcl

	//timer_.start (mac_->phyMib()->frameDuration() - .000001);		
		
}
/*
 *
 * class MeshMac
 *
 */

static class MeshMacClass : public TclClass {
public:
   MeshMacClass() : TclClass("Mac/16MESH_NEW") {}
   TclObject* create(int, const char*const*) {
      return (new MeshMac() );
   }
} class_mesh_mac;

MeshMac::MeshMac (): Mac()
{
	nodeId_ = 0 ;
	index_ = 0 ;
	

//	phyMib_ = new MeshPhyMib;	
//	macMib_ = new MeshMacMib(this);

//	coordinator_ = new MeshCoordinatorStandard(this , phyMib_);
//	bwmanager_ = new MeshBwManagerFairRR(this);
//	scheduler_ = new MeshSchedulerFairRR(this);

	ll_ = 0;
//	topology_ = 0;
	initialized_ = false;
	
//	forwarding_ = 0;
	
	nneighs_ = 0 ;

	hSelf_ = 0;
	hLast_ = 0;
	
	sponsorState_ = SS_IDLE;
	linkEstState_ = LE_IDLE;
	linkEstId_ = 0;
	sponsorStart_ = 0;
	linkEstStart_ = 0;
	linkEstCurrent_ = 0;

	scanStart_ = 0;
	scanMode_ = false;
	hErrorTagged_ = false;
	mshDschAvgError_ = -1.0;
	mshDschAvgGood_ = -1.0;
//added by qlj
	nMode_ = BS;
	nFlag_ = true;
	sNent_ = false;
	beSponsor_ = false;
	LNentTime_ = 0;
	nRandom_ = 0;
	rfragbuf_ = new MeshFragmentationBuffer;
	rreasbuf_ = new W_MeshReassemblyBuffer;

	hEstCurr_ = 0.1 ; // 参考tcl 
	hEstPast_ = 0.9 ; // 参考tcl
	actTimer_ = new ActiveNeighborTimer(this);
	
	linkId_ = 1;
	neighbors_.clear();	
	initialize ();

	tx_delay_ = 0;
}

int
MeshMac::command (int argc, const char*const* argv)
{
	if ( argc == 2 && strcmp (argv[1], "initialize") == 0 ) {
		initialize ();
		return TCL_OK;
//cancled by qlj
/*	} else if ( argc == 2 && strcmp (argv[1], "scan") == 0 ) {
		scanMode_ = true;
		scanStart_ = NOW;
		return TCL_OK;*/

	} else if ( argc == 2 && strcmp (argv[1], "h-error-tagged") == 0 ) {
		hErrorTagged_ = true;
		return TCL_OK;
//added by qlj
	} else if ( argc == 2 && strcmp (argv[1], "ss-mode") == 0 ) {
		nMode_ = SS;
		nFlag_ = false;
		scanMode_ = true;
		scanStart_ = NOW;
		return TCL_OK;
//cancled by qlj
/*	} else if ( argc == 2 && strcmp (argv[1], "link-establishment") == 0 ) {
		linkEstCurrent_ = 0;
		linkEstState_ = LE_SEND_CHALLENGE;
		linkEstStart_ = NOW;
		return TCL_OK;
	} else if ( argc == 3 && strcmp (argv[1], "open-sponsor") == 0 ) {
		sponsorId_ = (W_MeshNodeId) atoi (argv[2]);
		sponsorState_ = SS_SEND_REQ;
		sponsorStart_ = NOW;
		return TCL_OK;*/

/*/////////////////////////////////////////new add/////////////////2008.10.9////////////
//	} else if ( argc == 3 && strcmp (argv[1], "up-target") == 0) {
//		TclObject *obj;
//		if (*argv[2] == '0') {
				uptarget_ = 0;
				return (TCL_OK);
		}
		obj = TclObject::lookup(argv[2]);
		uptarget_ = (NsObject*) obj;
		if (uptarget_ == 0) {
//				tcl.resultf("no such object %s", argv[2]);
				return (TCL_ERROR);
		}
		return (TCL_OK);
//*////////////////////////////////重载log-target命令，因为 mac.cc中没有定义///////////
	} else if ( argc == 3 && strcmp(argv[1], "log-target") == 0) { 
			logtarget_ = (NsObject*) TclObject::lookup(argv[2]);
			if(logtarget_ == 0)
				return TCL_ERROR;
			return TCL_OK;	
///////////////////////////////////////////////////////////////////////////////////
	} else if ( argc == 3 && strcmp (argv[1], "phymib") == 0 ) {
		phyMib_ = (MeshPhyMib*) TclObject::lookup (argv[2]);

		coordinator_ = new MeshCoordinatorStandard(this , phyMib_);
		bwmanager_ = new MeshBwManagerFairRR(this);
		scheduler_ = new MeshSchedulerFairRR(this);
//coor要先初始化！因为其他类会调用他的邻居列表		
		coordinator_->initialize();
		scheduler_->initialize();
		bwmanager_->initialize();
		 
		actTimer_->handle((Event*) 0);

		return TCL_OK;
	} else if ( argc == 3 && strcmp (argv[1], "macmib") == 0 ) {
		macMib_ = (MeshMacMib*) TclObject::lookup (argv[2]);
		return TCL_OK;
	} else if ( argc == 3 && strcmp (argv[1], "ll") == 0 ) {
		ll_ = (LL*) TclObject::lookup (argv[2]);
		return TCL_OK;
//	} else if ( argc == 3 && strcmp (argv[1], "topology") == 0 ) {
//		topology_ = (MeshTopology*) TclObject::lookup (argv[2]);
//		return TCL_OK;
	} else if ( argc == 3 && strcmp (argv[1], "phy") == 0 ) {
		phy_.push_back ((MeshPhy*) TclObject::lookup (argv[2]));
		return TCL_OK;
	} else if ( argc == 3 && strcmp (argv[1], "channel") == 0 ) {
		channel_.push_back ((MeshChannel*) TclObject::lookup (argv[2]));
		return TCL_OK;
	} else if ( argc == 3 && strcmp (argv[1], "nodeid") == 0 ) {
		nodeId_ = (W_MeshNodeId) atoi (argv[2]);
		return TCL_OK;
	} else if ( argc == 3 && strcmp (argv[1], "index") == 0 ) {
		index_ = (W_MeshNodeId) atoi (argv[2]);
		return TCL_OK;
	} else if ( argc == 3 && strcmp (argv[1], "msh-dsch-avg-bad") == 0 ) {
		mshDschAvgError_ = atof (argv[2]);
		if ( mshDschAvgError_ > 0 && mshDschAvgError_ < 1.0 ) {
			fprintf (stderr, "Bad value '%f' for the average number of "
					"consecutive MSH-DSCH messages received incorrectly. "
					"Please select a number >= 1.\n", mshDschAvgError_);
			return TCL_ERROR;
		}
		return TCL_OK;
	} else if ( argc == 3 && strcmp (argv[1], "msh-dsch-avg-good") == 0 ) {
		mshDschAvgGood_ = atof (argv[2]);
		if ( mshDschAvgGood_ > 0 && mshDschAvgGood_ < 1.0 ) {
			fprintf (stderr, "Bad value '%f' for the average number of "
					"consecutive MSH-DSCH messages received correctly. "
					"Please select a number >= 1.\n", mshDschAvgGood_);
			return TCL_ERROR;
		}
		return TCL_OK;
	} else if ( argc == 3 && strcmp (argv[1], "scheduler") == 0 ) {
		if ( strcmp (argv[2], "fair-rr") == 0 ) {
			scheduler_ = new MeshSchedulerFairRR (this);
		} else {
			fprintf (stderr, "packet scheduler '%s' not supported", argv[2]);
			return TCL_ERROR;
		}
		return TCL_OK;
//	} else if ( argc == 3 && strcmp (argv[1], "forwarding") == 0 ) {
//		if ( strcmp (argv[2], "spf") == 0 ) {
//			forwarding_ = new MeshForwardingSpf (this, topology_);
//		} else if ( strcmp (argv[2], "dump") == 0 ) {
//			assert ( initialized_ );
//			return forwarding_->command ( argc - 2, argv + 2);
//			return TCL_OK;//added by qlj
//		} else {
//			fprintf (stderr, "forwarding module '%s' not supported", argv[2]);
//			return TCL_ERROR;
//		}
//		return TCL_OK;
	} else if ( argc == 3 && strcmp (argv[1], "bwmanager") == 0 ) {
		if ( strcmp (argv[2], "fair-rr") == 0 ) {
			//bwmanager_ = new MeshBwManagerFairRR (this);
		} else {
			fprintf (stderr, "bandwidth manager '%s' not supported", argv[2]);
			return TCL_ERROR;
		}
		return TCL_OK;
	} else if ( argc == 3 && strcmp (argv[1], "coordinator") == 0 ) {
		if ( strcmp (argv[2], "standard") == 0 ) {
         	coordinator_ = new MeshCoordinatorStandard (this, phyMib_);
		} else {
			fprintf (stderr, "coordinator '%s' not supported", argv[2]);
			return TCL_ERROR;
		}
		return TCL_OK;
	} else if ( argc == 3 && strcmp (argv[1], "dump") == 0 ) {
		if ( strcmp (argv[2], "profile") == 0 ) {
			std::map<W_MeshNodeId, unsigned int>::iterator it = neigh2ndx_.begin();
			for ( ; it != neigh2ndx_.end() ; it++ ) {
				fprintf (stderr, "%.9f %d -> %d profile %s alpha %d\n",
						NOW, nodeId_, it->first,
						W_MeshDebug::format(profile_[it->second]), alpha_[it->second]);
			}
		} else {
			return TCL_ERROR;
		}
		return TCL_OK;
	} else if ( argc == 3 && strcmp (argv[1], "estcurr") == 0 ) {
		hEstCurr_ = atof (argv[2]);
		if ( hEstCurr_ < 0 || hEstCurr_ > 1.0 ) {
			fprintf (stderr, "invalid weight '%f' for the current sample of "
					"the estimation of H. Choose a value in [0, 1]\n", hEstCurr_);
			return TCL_ERROR;
		}
		return TCL_OK;
	} else if ( argc == 3 && strcmp (argv[1], "estpast") == 0 ) {
		hEstPast_ = atof (argv[2]);
		if ( hEstPast_ < 0 || hEstPast_ > 1.0 ) {
			fprintf (stderr, "invalid weight '%f' for the past sample of "
					"the estimation of H. Choose a value in [0, 1]\n", hEstPast_);
			return TCL_ERROR;
		}
		return TCL_OK;
	} else if ( argc == 4 && strcmp (argv[1], "profile") == 0 ) {
		assert ( initialized_ );

		// get the burst profile index
		w_mesh::BurstProfile bp = (w_mesh::BurstProfile) atoi (argv[2]);

		if ( bp >= w_mesh::N_BURST_PROFILES ) {
			fprintf (stderr, "burst profile %d is not valid. "
					"Choose a number between 0 and %d\n",
					bp, w_mesh::N_BURST_PROFILES - 1);
			return TCL_ERROR;
		}

		// if the special keyword 'all' is used instead of the NodeID
		// of the neighbor, then the profile of all the links are updated
		if ( strcmp (argv[3], "all") == 0 ) {

			// get the list of this node's neighbors
			std::vector<W_MeshNodeId> neighbors;
			std::vector<W_MeshNodeId>::iterator it;
//			topology_->neighbors (nodeId_, neighbors);

			// for each neighbor, update the burst profile and alpha data
			// structures, and the MAC MIB
			for ( it = neighbors.begin() ; it != neighbors.end() ; ++it ) {
				unsigned int ndx = neigh2ndx_[*it];
				profile_[ndx] = bp;
				alpha_[ndx] = MeshPhyMib::alpha[bp];
				macMib_->updateBurstProfile ( nodeId(), *it, bp );
			}

		// otherwise, update only the specified burst profile
		} else {
			// get the neighbor NodeID
			W_MeshNodeId neigh = (W_MeshNodeId) atoi (argv[3]);

			if ( neigh2ndx_.count (neigh) != 1 ) {
				fprintf (stderr, "node %d is not a neighbor of node %d\n",
						nodeId_, neigh);
				return TCL_ERROR;
			}
			
			// get the neighbor index
			unsigned int ndx = neigh2ndx_[neigh];

			// update the burst profile & alpha data structures, and the MAC MIB
			profile_[ndx] = bp;
			alpha_[ndx] = MeshPhyMib::alpha[bp];
			macMib_->updateBurstProfile ( nodeId(), neigh, bp );
		}

		return TCL_OK;

	// try to send commands to the bandwidth manager
	} else if ( argc > 2 && strcmp (argv[1], "bwmanager") == 0 ) {
		assert ( initialized_ );
		return bwmanager_->command ( argc - 2, argv + 2);

	// try to send commands to the forwarding module
//	} else if ( argc > 2 && strcmp (argv[1], "forwarding") == 0 ) {
//		assert ( initialized_ );
//		return forwarding_->command ( argc - 2, argv + 2);

	// try to send commands to the coordinator
	} else if ( argc > 2 && strcmp (argv[1], "coordinator") == 0 ) {
		assert ( initialized_ );
		return coordinator_->command ( argc - 2, argv + 2);

	// try to send commands to the scheduler
	} else if ( argc > 2 && strcmp (argv[1], "scheduler") == 0 ) {
		assert ( initialized_ );
		return scheduler_->command (argc - 2, argv + 2);
	}

	return Mac::command(argc, argv);
}

void
MeshMac::initialize ()
{

	// this function must be called only once for each MAC object
	assert ( ! initialized_ );
//cancled by qlj. 以下的这些可以在建立邻居列表的时候添加

	// retrieve an array of neighbors of this node
	//std::vector<W_MeshNodeId> neighbors;
	//topology_->neighbors (nodeId_, neighbors);

	// set the number of neighbors of this node
	//nneighs_ = neighbors.size();
	

	// resize the arrays that hold one entry for each neighbor
	//alpha_.resize (nneighs_);
	//profile_.resize (nneighs_);
	//fragbuf_.resize (nneighs_);
	//reasbuf_.resize (nneighs_);
	//hNeigh_.resize (nneighs_);
	//hNeighLast_.resize (nneighs_);
	//ndx2neigh_.resize (nneighs_);
	//mshDschLinkQuality_.resize (nneighs_);

	// for each neighbor:
	// - set its local numerical identier (and the other way around)
	// - add a default transmission profile
	// - add a default alpha value
	// - create a fragmentation buffer
	// - create a reassembly buffer
	// - set to zero the estimated H value
	// - set to zero the last received opportunity time
	// - set the default burst profile in MAC Mib

	// 刚开始的时候没有任何邻居信息
	/*for ( unsigned int i = 0 ; i < nneighs_ ; i++ ) {
		neigh2ndx_[neighbors[i]] = i;
		ndx2neigh_[i] = neighbors[i];
		profile_[i] = w_mesh::QPSK_1_2;
		alpha_[i] = MeshPhyMib::alpha[w_mesh::QPSK_1_2];
		fragbuf_[i] = new MeshFragmentationBuffer;
		reasbuf_[i] = new W_MeshReassemblyBuffer;
		hNeigh_[i] = 0;
		hNeighLast_[i] = 0;
		//mshDschLinkQuality_[i].frames_ =
		//	geometric (mshDschRngGood_, 1/mshDschAvgGood_);
		
		macMib_->updateBurstProfile ( nodeId(), neighbors[i], 
											w_mesh::QPSK_1_2 );
	}*/


	// resize the internal data structures of the packet scheduler and
	// the bandwidth manager
//	scheduler_->initialize();
//	bwmanager_->initialize();
//	coordinator_->initialize();
//	forwarding_->initialize();

	// listen to the control channel
	//setControlChannel (w_mesh::RX);	
//added by qlj
	if (nMode_ == BS) {
		nFlag_ = true;
	} else {// 如果是新节点，启动扫描
		nFlag_ = false;
		scanMode_ = true;
		scanStart_ = NOW;
	}
	// set this MAC as initialized

	

	initialized_ = true;
//1	macMib_->timer().start (phyMib_->frameDuration() - .000001);
	//scheduler_->timer().start (phyMib()->controlDuration());

}

void
MeshMac::recv(Packet* pkt, Handler* h)
{

					//Packet::free(pkt);
					//return;	

	//printf( " node %d , send/recv a  message in mesh::recv() \n" , nodeId_);
	assert ( initialized_ );

	hdr_cmn *hdr = HDR_CMN(pkt);

	if(hdr->direction() == hdr_cmn::DOWN) {

		//callback_ = h;
		
		

		if ( W_MeshDebug::trace("WMAC::recvPacket") ) fprintf (stderr,
		"%.9f WMAC::recvPacket [%d] %s\n",
		NOW, nodeId_, W_MeshDebug::format (pkt));

/*		if ( hdr->ptype() == PT_AODV) {
			printf( " node %d , send a AODV message \n" , nodeId_);
			//h->handle((Event*) 0);		// new add 11.7
			downtarget_->recv(pkt,(Handler*)0);
		} else 	if ( hdr->ptype() == PT_ARP) {
			printf( " node %d , send a ARP message \n" , nodeId_);
			//callback_ = h;
			//h->handle((Event*) 0);		// new add 11.7
			downtarget_->recv(pkt,(Handler*)0);
		} else {			*/
			
			// we encapsulate the incoming IP datagram into a MAC SDU

//		if ( hdr_cmn::access(pkt)->ptype() == PT_CBR ) {
//			Packet::add();
//			Packet *newp = pkt->copy();		
//			mac_log(newp);

//		}

		W_MeshSdu* sdu = new W_MeshSdu;
		sdu->ip() = pkt;
			
	

		// pass the SDU to the appropriate function
		recvSdu (sdu);
		

		
        }
// 收到物理层发送上来的包
	else {	
		
//		Packet::free(p);

/*		if ( hdr->ptype()==PT_MAC_DATA || hdr->ptype()== PT_ARP ) {
			//callback_->handle((Event*) 0);
		}
		
		if ( hdr->ptype() == PT_AODV) {
			printf( " node %d , recv a AODV message \n" , nodeId_);
			uptarget_->recv(pkt,(Handler*)0);
		

		} else if ( hdr->ptype() == PT_ARP) {
			printf( " node %d , recv a ARP message \n" , nodeId_);
			//callback_->handle((Event*) 0);
			uptarget_->recv(pkt,(Handler*)0);
		
		}else {*/

		hdr_meshmac *hdr_ = HDR_MESHMAC(pkt);
		

		MeshBurst*  burst = hdr_->burst_ ;
// test 

//		burst->free();
		recvBurst ( burst) ;
//		Packet::free(pkt);		// 释放没用的packet
		
	
		//if (callback_) {
		//	callback_->handle((Event*) 0);
		//}

	}
}

void
MeshMac::recvSdu (W_MeshSdu* sdu)
{
	assert ( initialized_ );

	if ( W_MeshDebug::trace("WMAC::recvSdu") ) fprintf (stderr,
			"%.9f WMAC::recvSdu    [%d] %s\n",
			NOW, nodeId_, W_MeshDebug::format(sdu));
/*

	// 包的流程有所变化：无论包的终点是否本节点，都把包向上发；


	// if this node is the final destination of the SDU, then
	// we pass the encapsulated IP datagram to the upper layer (ie. LL)
	if ( (W_MeshNodeId) HDR_IP(sdu->ip())->daddr() == nodeId_ ) {
		HDR_CMN(sdu->ip())->direction () = hdr_cmn::UP;
//		ll_->recv (sdu->ip(), 0);
		 uptarget_->recv(sdu->ip(),(Handler*)0);
//		uptarget_->recv(sdu->ip(),this);
//		Scheduler::instance().schedule(uptarget_, sdu->ip(), 0);
		delete sdu;

	// otherwise, we first add our NodeID to the list of traversed hops,
	// and then encapsulate the MAC SDU into a MAC PDU, which is
	// buffered by the packet scheduler
	
	// 向下传～
	} else {

		// this is the IP packet incapsulated into the SDU
		Packet* ip = sdu->ip();

		// retrieve the flow ID of the IP datagram
		int fid = HDR_IP(ip)->flowid();

		// add our NodeID to the list of traversed hops
		sdu->addHop (nodeId_); 

		// timestamp the SDU to compute the access delay
		sdu->timestamp() = NOW;

		// create a new MAC PDU which encapsulates the MAC SDU
		W_MeshPdu* pdu = new W_MeshPdu;
		pdu->sdu() = sdu;

		// set the relevant fields of the MAC PDU
		pdu->nodeId() = nodeId_;
		// pdu->error() is false by default
		pdu->hdr().crc() = macMib_->flow2crc (fid);
		// pdu->hdr().fragmentation() is false by default
		pdu->hdr().mesh() = true;
		pdu->hdr().meshCid().type() = W_MeshMeshCid::DATA;
		// pdu->hdr().meshCid().reliability() is NO_ARQ by default
		pdu->hdr().meshCid().priority() = macMib_->flow2prio (fid);
		pdu->hdr().meshCid().drop() = macMib_->flow2drop (fid);
		
		//cancled by qlj.可以从普通包头中将下一跳地址写入
		pdu->hdr().meshCid().dst() = HDR_CMN(sdu->ip())->next_hop();
		pdu->size (sdu->size());

		// pass the new PDU to the packet scheduler
		scheduler_->addPdu (pdu);
	}
*/

	if ( HDR_CMN(sdu->ip())->direction () == hdr_cmn::DOWN) {

//		printf(" mac recv a down direction sdu");
		// this is the IP packet incapsulated into the SDU
		//Packet* ip = sdu->ip();

		// retrieve the flow ID of the IP datagram
		//int fid = HDR_IP(ip)->flowid();

		// add our NodeID to the list of traversed hops
		sdu->addHop (nodeId_); 

		// timestamp the SDU to compute the access delay
		sdu->timestamp() = NOW;

		// create a new MAC PDU which encapsulates the MAC SDU
		W_MeshPdu* pdu = new W_MeshPdu;
		pdu->sdu() = sdu;

		// set the relevant fields of the MAC PDU
		pdu->nodeId() = nodeId_;
		// pdu->error() is false by default
		//pdu->hdr().crc() = macMib_->flow2crc (fid);
		pdu->hdr().crc() = true;  // crc一直为true！～～参考tcl
		// pdu->hdr().fragmentation() is false by default
		pdu->hdr().mesh() = true;
		pdu->hdr().meshCid().type() = W_MeshMeshCid::DATA;
		// pdu->hdr().meshCid().reliability() is NO_ARQ by default
		// 参考tcl prio暂时全部为1
		//pdu->hdr().meshCid().priority() = macMib_->flow2prio (fid);
		pdu->hdr().meshCid().priority() = 1;
		//pdu->hdr().meshCid().drop() = macMib_->flow2drop (fid);
		// 参考tcl，全部为0
		pdu->hdr().meshCid().drop() = 0;		


		// by lhz 可以从普通包头中将下一跳地址写入
		
		pdu->size (sdu->size());
// 有待修改：应改为上层发下来的广播的包
		if((HDR_CMN(sdu->ip())->ptype() == PT_AODV) ||
				(HDR_CMN(sdu->ip())->ptype() == PT_ARP) ||
					  (HDR_IP(sdu->ip())->daddr() == IP_BROADCAST ) ) {
	//如果是路由层产生的包,设置dst为 BROADCAST = 0xFFFFFFFF 
		   if (nFlag_ == false)//没有接入网络的节点不能发送包
			delete pdu;			
		   else {			
			pdu->hdr().meshCid().dst() = w_mesh::BROADCAST;
			rflow_.queue_.push(pdu);
			rflow_.size_ += pdu->size();
			rflow_.gnt_size_ += pdu->size();
		   }
		} else {
			
			W_MeshNodeId dstN_ = HDR_CMN(sdu->ip())->next_hop();
			int occurs = neigh2ndx_.count(dstN_);
				
			if ( occurs == 0 ) {
				printf ( "收到不是给邻居的包\n" ) ;	//上层发送下来的包的下一跳节点

				sdu->freePayload();
				sdu->ip() = 0 ;
				delete sdu;
				sdu = 0;
				delete pdu;
				pdu = 0;
				
				return;
			}
			pdu->hdr().meshCid().dst() = HDR_CMN(sdu->ip())->next_hop();
			// pass the new PDU to the packet scheduler
			scheduler_->addPdu (pdu);
		}
// 向上发送的,无论包的终点是否本节点，都把包向上发
	 } else {
//		HDR_CMN(sdu->ip())->direction () = hdr_cmn::UP;
//		ll_->recv (sdu->ip(), 0);
//		 uptarget_->recv(sdu->ip(),(Handler*)0);
//		uptarget_->recv(sdu->ip(),this);
//		Scheduler::instance().schedule(uptarget_, sdu->ip(), tx_delay_);
//		tx_delay_ += 0.000050000;
//11.4		delete sdu;
	}

}

void
MeshMac::recvMshDsch (MeshMshDsch* dsch, double txtime)
{
	assert ( initialized );

	if ( W_MeshDebug::trace("WMAC::recvMshDsch") ) fprintf (stderr,
			"%.9f WMAC::recvMshDsch[%d]\n", NOW, nodeId_);

	// add by lhz 先添加，再跟新
	coordinator_->recvMshDsch (dsch, txtime);
	
	// update the H value of this neighbor
	W_MeshNodeId snode = dsch->myself().nodeId_;
	unsigned int ndx  = neigh2ndx_[snode];
	Stat::put ("mesh_dsch_inter_frame_rcv", index_,
			round ( ( NOW - hNeighLast_[ndx] ) / phyMib_->frameDuration() ) );
	Stat::put ("mesh_dsch_inter_time_rcv", index_, NOW - hNeighLast_[ndx]);
	Stat::put ("mesh_dsch_inter_time_rcv_d", index_, NOW - hNeighLast_[ndx]);
	
	
	updateH (hNeigh_[ndx], hNeighLast_[ndx]);

	// compute the difference between the actual next transmit time
	// and the estimated (H) value, if this is the tagged node for this metric
	if ( hErrorTagged_ ) {
		double diff = fabs ( dsch->myself().nextXmtTimeSec_ - hNeigh_[ndx] );
		//
		// [CC] not sure whether it is correct to mix together the
		// samples collected from different neighbors (uncommented line below)
		// while I believe it is ok to get separate statistics (commented line
		// below). However, the latter makes scripts more difficult, thus
		// for now I will stick to the easy & dirty way.
		// 
		// Stat::put ("mesh_dsch_h_error", snode, diff);
		Stat::put ("mesh_dsch_h_error", index_, diff);
	}

	// send the MSH-DSCH message to the coordinator and to the bw manager
	//coordinator_->recvMshDsch (dsch, txtime);
	bwmanager_->recvMshDsch (dsch);
//	forwarding_->recvMshDsch (dsch);
}

void
MeshMac::recvMshNcfg (MeshMshNcfg* ncfg, double txtime)
{
	assert ( initialized );

	if ( W_MeshDebug::trace("WMAC::recvMshNcfg") ) fprintf (stderr,
			"%.9f WMAC::recvMshNcfg[%d]\n", NOW, nodeId_);

	
	coordinator_->recvMshNcfg (ncfg, txtime);//update the neighbor infomation
//cancled by qlj
	/*if ( scanMode_ ) {
		// fprintf (stderr, "%.9f MSH-NCFG received from node %d\n",
		//		NOW, ncfg->src());
		if ( scanSet_.count (ncfg->src()) == 1 ) {
			Stat::put ("mesh_scan_latency", index_, NOW - scanStart_);
			char** argv = new char*[1];
			argv[0] = "print";
			Stat::command (1, argv);
			exit (0);
		}
		scanSet_.insert (ncfg->src());
	}*/
//added by qlj
	//如果是新节点，则启动扫描 这个在initialize里实现
/*	if(nFlag==false)
	{	scanMode_ = true;
		scanStart_ = NOW;
	}*/
	if ( scanMode_ ) {
		//发送节点如果能成为赞助节点，则插入到set中
		if (ncfg->beSponsor () == false)
			scanSetAvl_.insert (ncfg->src());
		//是否从一个节点收到两个ncfg，如果是则在下一个发送时间，发送nent
		if (scanSet_.count (ncfg->src()) == 1 && scanSetAvl_.size() != 0 )	
		{
			Stat::put ("mesh_scan_latency", index_, NOW - scanStart_);
		//从scanSet中选择一个节点作为sponsor node，从scanSetAvl_中选最后一个
		// 随机选取赞助节点
			int num = scanSetAvl_.size() ;
			srand ((unsigned)time(0));
			num = (rand()%num);
			std::set<W_MeshNodeId>::iterator sp_= scanSetAvl_.begin();
			for(int i=0;i<num;i++) // 有待完善
				sp_++;			
			sponsorId_ = *sp_;
			sponsorState_ = SS_SEND_REQ;	//有待发送req
//			nRandom_ = nRandom();
			nRandom_ = 0 ;
			sponsorStart_ = NOW;
			scanMode_ = false;
		} else {
			scanSet_.insert (ncfg->src());
			
		}
	}
	//如果收到sponsornode的net－entry－open，则发送一个回复，表示节点已经加入网络
	if ( ncfg->type() == MeshMshNcfg::NET_ENTRY_OPEN &&
			ncfg->hdr().meshCid().dst() == nodeId_ ) {
		sponsorState_ = SS_SEND_ACK;	//有待发送ack
		sNent_ = false;//允许发送nentACK消息		？？？？？？？？
		//nFlag==true；	
	}

//

	// fprintf (stderr, "** node %d from node %d to node %d type %d\n",
	//		nodeId_, ncfg->src(), ncfg->hdr().meshCid().dst(),
	//		ncfg->type());
	if ( ncfg->type() == MeshMshNcfg::CHALLENGE &&
			ncfg->hdr().meshCid().dst() == nodeId_ ) {
		// fprintf (stderr, "%.9f node %d LE_SEND_CHALLENGE from node %d\n",
		//		NOW, nodeId_, ncfg->src());
		linkEstState_ = LE_SEND_RESPONSE;
		linkEstId_ = ncfg->src();
	} else if ( ncfg->type() == MeshMshNcfg::RESPONSE &&
			ncfg->hdr().meshCid().dst() == nodeId_ ) {
		// fprintf (stderr, "%.9f node %d LE_SEND_RESPONSE from node %d\n",
		//		NOW, nodeId_, ncfg->src());
		linkEstState_ = LE_SEND_ACK;
	} 
}

void
MeshMac::recvMshNent (MeshMshNent* nent, double txtime)
{
	assert ( initialized );

	if ( W_MeshDebug::trace("WMAC::recvMshNent") ) fprintf (stderr,
			"%.9f WMAC::recvMshNent[%d]\n", NOW, nodeId_);

	// This MSH-NENT is directed to myself. Thus, a MSH-NCFG message
	// is scheduled to be sent back to the new node.
//cancled by qlj
	/*if ( nent->hdr().meshCid().dst() == nodeId_ ) {
		// fprintf (stderr, "%.9f node %d SS_SEND_OPEN from node %d\n",
		//	NOW, nodeId_, nent->src());
		sponsorState_ = SS_SEND_OPEN;
		sponsorId_ = nent->src();
	}*/
//added by qlj
//收到一个nent，如果是request，则在下一个ncfg消息中发送net－entry－open，如果是ack表示接入完成。
	if ( nent->hdr().meshCid().dst() == nodeId_ && nFlag () ) {

	     if (nent->type() == MeshMshNent::REQUEST && beSponsor_ !=true ) {
			sponsorState_ = SS_SEND_OPEN;
			sponsorId_ = nent->src();
			beSponsor_ = true;
	     } else if(nent->type() == MeshMshNent::ACK && beSponsor_==true && sponsorId_ == nent->src() ) {
		//  if (beSponsor_==true) {//判断是否已经是赞助节点。
			sponsorState_ = SS_IDLE;
			beSponsor_ = false;
			// 添加新的邻居节点
			coordinator_->recvMshNent (nent);
	
	     } else {
			printf ("mesh_mac.cc:876 出错 ");
			//abort ();
	     }
	}

//11.4	delete nent;	
}

void
MeshMac::opportunity (MeshMshDsch* dsch)
{
	assert ( initialized );

	if ( W_MeshDebug::trace ("WMAC::opportunity") ) fprintf (stderr,
			"%.9f WMAC::opportunity[%d] MSH-DSCH\n", NOW, nodeId_);

	// let the bandwidth manager fill the remaining field of the MSH-DSCH message
	bwmanager_->schedule (dsch);

	// encapsulate the MSH-DSCH into a PDU burst
	MeshBurst* burst = new MeshBurst;
	burst->addMshDsch (dsch);
	burst->source() = nodeId_;

	if ( W_MeshDebug::trace ("WMAC::opportunity") )
		W_MeshDebug::print (dsch, stderr);

	Stat::put ("mesh_dsch_inter_frame_snd", index_,
		round ( ( NOW - hLast_ ) / phyMib_->frameDuration() ) );
	Stat::put ("mesh_dsch_inter_time_snd", index_, NOW - hLast_);
	Stat::put ("mesh_dsch_inter_time_snd_d", index_, NOW - hLast_);
	Stat::put ("mesh_dsch_size_a", index_, dsch->size());
	Stat::put ("mesh_dsch_size_d", index_, dsch->size());

	// update the estimated interval between two consecutive opportunities
	updateH (hSelf_, hLast_);

	// set the PHY in tx mode to the control channel
//	setControlChannel (w_mesh::TX);

//////////////////////////////////////new add 修改原来代码的接口，把burst放到packet中////////

//	Packet *p = Packet::alloc ();//分配一个空包	
//	struct hdr_cmn *hdr=HDR_CMN(p);
//	struct hdr_mac *mac=HDR_MAC(p);
//	struct hdr_meshmac *meshmac=HDR_MESHMAC(p);
//	//设置普通头部信息
//	hdr->uid()=0;
//	hdr->ptype() = PT_MAC_DSCH;	//有待添加自己的ptype
//	hdr->timestamp()=NOW;
//	meshmac->burst_ = burst;

/////////////////////////////////////NEW ADD 以IE为单位，在downtarget中打印出来//////
/*补丁中IE加入顺序：	1.avlIE
			2.conIE
			3.regantIE
			4.gntIE
			5.reqIE
由于2。3。4是同类，很难区分，所以2.3.4作为一类，同时打印

实际打印顺序 ： 1.avlIE；2.conIE，regantIE，gntIE；3.reqIE
*/




//////////////////////////////////跟踪avlIE/////////////////////////// 有待改进！！！！


	list<MeshMshDsch::AvlIE>::iterator avl_IE = burst->mshDsch()->avl ().begin();
		for( ;
		avl_IE != ( burst->mshDsch() )->avl().end(); ++ avl_IE ) {
	
		Packet *p = Packet::alloc ();//分配一个空包	
		struct hdr_cmn *hdr=HDR_CMN(p);
		struct hdr_mac *mac=HDR_MAC(p);
		struct hdr_meshmac *meshmac=HDR_MESHMAC(p);
		//设置普通头部信息
//		hdr->uid()=0;
		hdr->ptype() = PT_MAC_DSCH_AVL;	//有待添加自己的ptype
		hdr->timestamp()=NOW;
		meshmac->src_ = nodeId_ ;
//		meshmac->dst_ = nodeId_ ;	
		mac_log( p );
		}


//////////////////////////////////跟踪gnt//////////////////////
	list<MeshMshDsch::GntIE>::iterator gnt_IE = burst->mshDsch()->gnt ().begin();
		
		for( ;
		gnt_IE != ( burst->mshDsch() )->gnt().end(); ++ gnt_IE ) {
	
		Packet *p = Packet::alloc ();//分配一个空包	
		struct hdr_cmn *hdr=HDR_CMN(p);
		struct hdr_mac *mac=HDR_MAC(p);
		struct hdr_meshmac *meshmac=HDR_MESHMAC(p);
		//设置普通头部信息
//		hdr->uid()=0;
		if( gnt_IE->fromRequester_ == true ) {
			hdr->ptype() = PT_MAC_DSCH_CON;	//有待添加自己的ptype
		} else 	hdr->ptype() = PT_MAC_DSCH_GNT;	
		hdr->timestamp()=NOW;

		meshmac->src_ = nodeId_ ;
		meshmac->dst_ = gnt_IE->nodeId_ ;	

		mac_log( p );
		}

///////////////////////////////////////跟踪req//////////////////////////////////
			
	list<MeshMshDsch::ReqIE>::iterator req_IE = burst->mshDsch()->req ().begin();
		for( ;
		req_IE != ( burst->mshDsch() )->req().end(); ++ req_IE ) {
	
		Packet *p = Packet::alloc ();//分配一个空包	
		struct hdr_cmn *hdr=HDR_CMN(p);
		struct hdr_mac *mac=HDR_MAC(p);
		struct hdr_meshmac *meshmac=HDR_MESHMAC(p);
		//设置普通头部信息
//		hdr->uid()=0;
		hdr->ptype() = PT_MAC_DSCH_REQ;	//有待添加自己的ptype
		hdr->timestamp()=NOW;
		meshmac->req_ = req_IE ;
// 测试req
		W_MeshNodeId NodeId_ =  req_IE->nodeId_ ;
		//! Demand level (8 bits).
		unsigned char Level_ = req_IE->level_ ;
		//! Demand persistence (3 bits).
		MeshMshDsch::Persistence Persistence_=req_IE->persistence_;

		meshmac->src_ = nodeId_ ;
		meshmac->dst_ = req_IE->nodeId_ ;	
			
		//跟踪从mac层向phy层发送的burst
		mac_log( p );
		}


/*
/////////////////////////////////////////////////////////////////////

	
	// send the burst using sendBurst(burst)
	// phy_[0]->sendBurst (burst);

*/
	Packet *p = Packet::alloc ();//分配一个空包	有待改进
	struct hdr_cmn *hdr=HDR_CMN(p);
	//struct hdr_mac *mac=HDR_MAC(p);
	struct hdr_meshmac *meshmac=HDR_MESHMAC(p);
	//设置普通头部信息
	hdr->uid()=0;
	hdr->ptype() = PT_MAC_DSCH;	//有待添加自己的ptype
	hdr->timestamp()=NOW;
	hdr->direction()= hdr_cmn::DOWN ;
	hdr->size_ = burst->size();
	meshmac->burst_ = burst;

//计算突发在channel中传输时间
	int burstsize_ = hdr-> size_ ;
	w_mesh::BurstProfile mod = phyMib_->GetModulation ();
	hdr->txtime_ = phyMib_-> GetTrxTime (burstsize_ , mod);	
	burst->txtime() = hdr->txtime_ ;

	//printf( " node %d , send a  dsch  message  \n" , nodeId_);
	downtarget_->recv(p,(Handler*)0);



}

void
MeshMac::opportunity (MeshMshNcfg* ncfg)
{
	assert ( initialized );

	if ( W_MeshDebug::trace ("WMAC::opportunity") ) fprintf (stderr,
			"%.9f WMAC::opportunity[%d] MSH-NCFG\n", NOW, nodeId_);

	Stat::put ("mesh_ncfg_inter_frame", index_,
		round ( ( NOW - hLastNcfg_ ) / phyMib_->frameDuration() ) );
	Stat::put ("mesh_ncfg_inter_time", index_, NOW - hLastNcfg_);
	hLastNcfg_ = NOW;

	// encapsulate the MSH-DSCH into a PDU burst
	MeshBurst* burst = new MeshBurst;
	burst->addMshNcfg (ncfg);

	ncfg->src() = nodeId_;
	burst->source() = nodeId_;
//added by qlj.用来判断本节点是不是正在赞助节点。True表示已经为某个节点的赞助节点
	if (beSponsor_ == true)
		 ncfg->beSponsor() = true;
	else
		 ncfg->beSponsor() = false;		

	// If there is a pending MSH-NCFG Net Entry Open message, send it now.
	if ( sponsorState_ == SS_SEND_OPEN ) {
		ncfg->type() = MeshMshNcfg::NET_ENTRY_OPEN;
		ncfg->hdr().meshCid().dst() = sponsorId_;
//cancled by qlj.当收到新节点的ACK时，才将状态置为SS_IDLE
		//sponsorState_ = SS_IDLE;
	}

//cancled by qlj,as we don't need it any more
	// get the list of this node's neighbors
/*	std::vector<W_MeshNodeId> neighbors;
	topology_->neighbors (nodeId_, neighbors);

	if ( linkEstState_ == LE_SEND_CHALLENGE ) {
		ncfg->hdr().meshCid().dst() = neighbors[linkEstCurrent_];
		ncfg->type() = MeshMshNcfg::CHALLENGE;
		linkEstState_ = LE_WAIT_RESPONSE;
		// fprintf (stderr, "%.9f node %d LE_SEND_CHALLENGE to node %d\n",
		//		NOW, nodeId_, ncfg->hdr().meshCid().dst());

	} else if ( linkEstState_ == LE_SEND_ACK ) {
		// fprintf (stderr, "%.9f node %d LE_SEND_ACK to node %d\n",
		//		NOW, nodeId_, neighbors[linkEstCurrent_]);
		linkEstCurrent_++;
		linkEstState_ = LE_SEND_CHALLENGE;

		if ( linkEstCurrent_ >= neighbors.size() ) {
			Stat::put ("mesh_linkest_latency", index_, NOW - linkEstStart_);
			char** argv = new char*[1];
			argv[0] = "print";
			Stat::command (1, argv);
			exit (0);
		}

	} else if ( linkEstState_ == LE_SEND_RESPONSE ) {
		// fprintf (stderr, "%.9f node %d LE_SEND_RESPONSE to node %d\n",
		// 		NOW, nodeId_, linkEstId_);
		ncfg->hdr().meshCid().dst() = linkEstId_;
		ncfg->type() = MeshMshNcfg::RESPONSE;
		linkEstState_ = LE_IDLE;
	}*/

//

	// set the PHY in tx mode to the control channel
	//setControlChannel (w_mesh::TX);

/////////////////////////////////new add 把burst放到packet中，把ncfg信息打印出来
	Packet *p = Packet::alloc ();//分配一个空包	
	struct hdr_cmn *hdr=HDR_CMN(p);
	//struct hdr_mac *mac=HDR_MAC(p);
	struct hdr_meshmac *meshmac=HDR_MESHMAC(p);
	//设置普通头部信息
//	hdr->uid()=0;
	hdr->ptype() = PT_MAC_NCFG;	//有待添加自己的ptype
	hdr->timestamp()=NOW;
	hdr->direction()= hdr_cmn::DOWN ;
	hdr->size_ = burst->size();
	meshmac->burst_ = burst;

	//计算突发在channel中传输时间
	int burstsize_ = hdr-> size_ ;
	w_mesh::BurstProfile mod = phyMib_->GetModulation ();
	hdr->txtime_ = phyMib_-> GetTrxTime (burstsize_ , mod);	
	burst->txtime() = hdr->txtime_ ;

	//printf( " node %d , send a  ncfg message  \n" , nodeId_);
	// new add  跟踪从mac层向phy层发送的burst
	downtarget_->recv(p,(Handler*)0);


	// send the burst using sendBurst(burst)
	//phy_[0]->sendBurst (burst);
}

void
MeshMac::opportunity (MeshMshNent* nent)
{
	assert ( initialized );

	if ( W_MeshDebug::trace ("WMAC::opportunity") ) fprintf (stderr,
			"%.9f WMAC::opportunity[%d] MSH-NENT\n", NOW, nodeId_);

	Stat::put ("mesh_nent_inter_frame", index_,
		round ( ( NOW - hLastNent_ ) / phyMib_->frameDuration() ) );
	Stat::put ("mesh_nent_inter_time", index_, NOW - hLastNent_);
//	hLastNent_ = NOW;

	if ( sponsorState_ != SS_SEND_REQ && sponsorState_ != SS_SEND_ACK ) {
		delete nent;
		return;
	}
//cancled by qlj
	/*if ( sponsorState_ == SS_SEND_REQ ) {
		// fprintf (stderr, "%.9f node %d SS_SEND_REQ to node %d\n",
		//	NOW, nodeId_, sponsorId_);
		nent->type() = MeshMshNent::REQUEST;
		sponsorState_ = SS_SEND_ACK;
	} else if ( sponsorState_ == SS_SEND_ACK ) {
		// nent->type() = MeshMshNent::ACK;
		// sponsorState_ = SS_IDLE;
		Stat::put ("mesh_sponsor_latency", index_, NOW - sponsorStart_);
      char** argv = new char*[1];
      argv[0] = "print";
      Stat::command (1, argv);
      exit (0);
	}
	else
		abort ();*/
//added by qlj。
//如果是REQUEST状态则发送接入请求消息，如果是ACK状态，则发送ACK消息
//并设置sponsorState_ 为 SS_IDLE表示接入网络过程完成,nFlag为true表示节点成为网络的一员

	if (sNent_ == true) {//如果节点已经发送了nent请求消息
		if( ( NOW-LNentTime_ )>0.5) { //当超时1s后重新启动扫描 by lhz  3.17
			scanMode_ = true;
			scanStart_ = NOW;
			sNent_ = false;
			LNentTime_ = 0;
//清空SET
			scanSet_.clear();
			scanSetAvl_.clear();
			delete nent;
			return ;
		} else {//没有超时时，不发该请求
			delete nent;
			return;
		}
			
	} else {//如果节点没有发nent请求消息，或者已经收到NET－ENTRY－OPEN消息		
	
		if ( sponsorState_ == SS_SEND_REQ ) {//没有发nent请求消息，则发送，并设置为已经发了
		// fprintf (stderr, "%.9f node %d SS_SEND_REQ to node %d\n",
		//	NOW, nodeId_, sponsorId_);
		    if (nRandom_ == 0) {		
			nent->type() = MeshMshNent::REQUEST;
			LNentTime_ = NOW;
			sNent_ = true; 
		    } else {
			--nRandom_;
			delete nent;
			return ;
; }
		} else if ( sponsorState_ == SS_SEND_ACK ) {//已经收到NET－ENTRY－OPEN消息,则发送ACK消息
			 nent->type() = MeshMshNent::ACK;
			 sponsorState_ = SS_IDLE;
			 nFlag_ = true;
			Stat::put ("mesh_sponsor_latency", index_, NOW - sponsorStart_);
			printf( " 节点 %d 成为全功能节点" , nodeId_ );
			
     	 	}else	{
			printf( " 程序mesh_mac.cc line 1240 出错" );
			abort ();
		}
	}
//

	nent->hdr().meshCid().dst() = sponsorId_;
	nent->src() = nodeId_;

	MeshBurst* burst = new MeshBurst;
	burst->addMshNent (nent);
	burst->source() = nodeId_;

	// set the PHY in tx mode to the control channel
	//setControlChannel (w_mesh::TX);

/////////////////////////////////new add 把burst放到packet中，把nent信息打印出来
	Packet *p = Packet::alloc ();//分配一个空包	
	struct hdr_cmn *hdr=HDR_CMN(p);
	//struct hdr_mac *mac=HDR_MAC(p);
	struct hdr_meshmac *meshmac=HDR_MESHMAC(p);
	//设置普通头部信息
//	hdr->uid()=0;
	hdr->ptype() = PT_MAC_NENT;	//有待添加自己的ptype
	hdr->timestamp()=NOW;
	hdr->direction()= hdr_cmn::DOWN ;
	hdr->size_ = burst->size();
	meshmac->burst_ = burst;

	//计算突发在channel中传输时间
	int burstsize_ = hdr-> size_ ;
	w_mesh::BurstProfile mod = phyMib_->GetModulation ();
	hdr->txtime_ = phyMib_-> GetTrxTime (burstsize_ , mod);
	burst->txtime() = hdr->txtime_ ;	

	//printf( " node %d , send a  nent message  \n" , nodeId_);
	// new add  跟踪从mac层向phy层发送的burst
	downtarget_->recv(p,(Handler*)0);


	// send the burst using sendBurst(burst)
	//phy_[0]->sendBurst (burst);
}

void
MeshMac::recvBurst (MeshBurst* burst)
{
	assert ( initialized );


//test
//	return;





	if ( W_MeshDebug::trace("WMAC::recvBurst") ) {
		fprintf (stderr,
			"%.9f WMAC::recvBurst  [%d] src %d error %d\n",
			NOW, nodeId_, burst->source(), burst->error());
		W_MeshDebug::print (burst, stderr);
	}

	//
	// manage a control message
	//
	if ( burst->type() == w_mesh::MSHDSCH ) {
		// check if the burst needs be corrupted and update
		// the quality of the current link
		//
	

		if ( mshDschAvgError_ > 0 && mshDschAvgError_ > 0 ) {
			// get the quality of the sender node's link

// by lhz 11.26 增强稳定性
			int occours = neigh2ndx_.count( burst->source() );
			if ( occours == 1 ) {
			
			LinkQuality& link = mshDschLinkQuality_[neigh2ndx_[burst->source()]];

			// if the link is bad, corrupt the burst
			// otherwise, leave the error flag unaltered (can be true)
			// 关闭了链路控制的功能 by lhz ，10.28
			//if ( ! link.good_ ) burst->error() = true;

			// decrease the number of frames before transition
			// if this counter reaches zero, then flip the link quality
			if ( --link.frames_ == 0 ) {
				// select the number of frames to go
				if ( ! link.good_ )
					link.frames_ = geometric (mshDschRngGood_, 1/mshDschAvgGood_);
				else
					link.frames_ = geometric (mshDschRngError_, 1/mshDschAvgError_);

				// flip the link quality status
				link.good_ = ! link.good_;
			}

			}// end if line:1395
		}

		// actually decode data contained into the MSH-DSCH message
		// if the burst is not corrupted
		if ( ! burst->error() ) {
			Stat::put ("mesh_dsch_error", index_, 0.0);

//////////////////////////////////////NEW ADD 以IE为单位，在logtrace中打印出来////////////////////////////////////////////////////////////////
/*打印顺序：	//1.myIE
		2.gntIE(conIE)
		3.avlIE
		4.reqIE
*/

/*/////////////////////////////////跟踪gnt//////////////////////
	list<MeshMshDsch::GntIE>::iterator gnt_IE = burst->mshDsch()->gnt ().begin();
		
		for( ;
		gnt_IE != ( burst->mshDsch() )->gnt().end(); ++ gnt_IE ) {
	
		Packet *p = Packet::alloc ();//分配一个空包	
		struct hdr_cmn *hdr=HDR_CMN(p);
		//struct hdr_mac *mac=HDR_MAC(p);
		struct hdr_meshmac *meshmac=HDR_MESHMAC(p);
		//设置普通头部信息
//		hdr->uid()=0;
		if( gnt_IE->fromRequester_ == true ) {
			hdr->ptype() = PT_MAC_DSCH_CON;	//有待添加自己的ptype
		} else 	hdr->ptype() = PT_MAC_DSCH_GNT;	
		hdr->timestamp()=NOW;
		meshmac->gnt_ = gnt_IE ;	
		mac_log(p);	//logtarget_是私有变量，通过mac_log 来把p传给它；
		}


//////////////////////////////////跟踪avlIE////////////////////////////////////
	list<MeshMshDsch::AvlIE>::iterator avl_IE = burst->mshDsch()->avl ().begin();
		for( ;
		avl_IE != ( burst->mshDsch() )->avl().end(); ++ avl_IE ) {
	
		Packet *p = Packet::alloc ();//分配一个空包	
		struct hdr_cmn *hdr=HDR_CMN(p);
		//struct hdr_mac *mac=HDR_MAC(p);
		struct hdr_meshmac *meshmac=HDR_MESHMAC(p);
		//设置普通头部信息
//		hdr->uid()=0;
		hdr->ptype() = PT_MAC_DSCH_AVL;	//有待添加自己的ptype
		hdr->timestamp()=NOW;
		meshmac->avl_ = avl_IE ;	
		mac_log(p);	//logtarget_是私有变量，通过mac_log 来把p传给它；
		}

///////////////////////////////////////跟踪req//////////////////////////////////
			
	list<MeshMshDsch::ReqIE>::iterator req_IE = burst->mshDsch()->req ().begin();
		for( ;
		req_IE != ( burst->mshDsch() )->req().end(); ++ req_IE ) {
	
		Packet *p = Packet::alloc ();//分配一个空包	
		struct hdr_cmn *hdr=HDR_CMN(p);
		//struct hdr_mac *mac=HDR_MAC(p);
		struct hdr_meshmac *meshmac=HDR_MESHMAC(p);
		//设置普通头部信息
//		hdr->uid()=0;
		hdr->ptype() = PT_MAC_DSCH_REQ;	//有待添加自己的ptype
		hdr->timestamp()=NOW;
		meshmac->req_ = req_IE ;

// 测试req
		W_MeshNodeId NodeId_ =  req_IE->nodeId_ ;
		//! Demand level (8 bits).
		unsigned char Level_ = req_IE->level_ ;
		//! Demand persistence (3 bits).
		MeshMshDsch::Persistence Persistence_=req_IE->persistence_;

		
		mac_log(p);	//logtarget_是私有变量，通过mac_log 来把p传给它；
		}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
		//printf( " node %d , recv  a  dsch message  \n" , nodeId_);
		recvMshDsch (burst->mshDsch(), burst->txtime());
		} else {
			Stat::put ("mesh_dsch_error", index_, 1.0);
		}

	} else if ( burst->type() == w_mesh::MSHNCFG ) {
		if ( ! burst->error() ) {

		//printf( " node %d , recv  a  ncfg message  \n" , nodeId_);
/*///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////		
			Packet *p = Packet::alloc ();//分配一个空包	
			struct hdr_cmn *hdr=HDR_CMN(p);
			//struct hdr_mac *mac=HDR_MAC(p);
			//struct hdr_meshmac *meshmac=HDR_MESHMAC(p);
			//设置普通头部信息
			//hdr->uid()=0;
			hdr->ptype() = PT_MAC_NCFG;	//有待添加自己的ptype
			hdr->timestamp()=NOW;
			
			mac_log(p);	//logtarget_是私有变量，通过mac_log 来把p传给它；
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
			recvMshNcfg (burst->mshNcfg(), burst->txtime());
		}
	} else if ( burst->type() == w_mesh::MSHNENT ) {
		if ( ! burst->error() ) {
/*////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			//printf( " node %d , recv  a  nent message  \n" , nodeId_);
			
			Packet *p = Packet::alloc ();//分配一个空包	
			struct hdr_cmn *hdr=HDR_CMN(p);
			//struct hdr_mac *mac=HDR_MAC(p);
			//struct hdr_meshmac *meshmac=HDR_MESHMAC(p);
			//设置普通头部信息
			//hdr->uid()=0;
			hdr->ptype() = PT_MAC_NENT;	//有待添加自己的ptype
			hdr->timestamp()=NOW;
			
			mac_log(p);	//logtarget_是私有变量，通过mac_log 来把p传给它；
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
			recvMshNent (burst->mshNent(), burst->txtime());

		}
	// manage a data burst
	//
	} else {
//		return;	// 3.20
		// 12.2 非完全功能节点不能接受数据信息
		if ( ! nFlag () ) {
//			burst->free();
			return;
		}
		//printf( " node %d , recv  a  data message  \n" , nodeId_);

		// remove PDUs one by one from the burst
		std::list<W_MeshPdu*>::iterator it;
		tx_delay_ = 0;
		for (it = burst->pdus().begin() ; it !=burst->pdus().end(); it++) {
			
			W_MeshPdu* pdu ;
			pdu = *it;




			// if the PDU does not contain errors, then we check for the
			// destination NodeID in the CID in the MAC header
			// if the PDU is directed to this node, we pass it to the
			// appropriate reassembly buffer
			if ( ! burst->error() && ! pdu->error() &&
					pdu->hdr().meshCid().dst() == nodeId_ ) {

//				continue;
				
				Stat::put ("mesh_mac_tpt", index_, pdu->size());
// by lhz 11.26 增强稳定性
// 可能会导致内存泄露～
				int occours = neigh2ndx_.count( pdu->nodeId() );
				if ( occours == 0 ) {
					printf("收到给我的包，但我的邻居类表中没有它");
					continue;
				}

				W_MeshSdu* sdu = reasbuf_[neigh2ndx_[pdu->nodeId()]]->addPdu (pdu);
				// if a full SDU is reassembled, then reschedule it to recvSDU
				if ( sdu ) {
					// compute the per-hop delay
					const int fid = HDR_IP(sdu->ip())->flowid();
					const double delay = NOW - sdu->timestamp();
					Stat::put ("mesh_delay_access_a", fid, delay);
					Stat::put ("mesh_delay_access_d", fid, delay);
					Stat::put ("mesh_delay_hopbyhop_a", index_, delay);
					Stat::put ("mesh_delay_hopbyhop_d", index_, delay);

					// indicate to the bandwidth manager that we received an SDU
					bwmanager_->received (
							HDR_IP(sdu->ip())->saddr(),
							HDR_IP(sdu->ip())->daddr(),
							pdu->hdr().meshCid().priority(),
							neigh2ndx_[sdu->lastHop()], pdu->size()
							);
					
//					HDR_CMN(sdu->ip())->direction () = hdr_cmn::UP;
//					recvSdu (sdu);
//
					Packet* p = pdu->sdu()->ip()->copy();
					HDR_CMN(p)->direction () = hdr_cmn::UP;
					
//					if ( hdr_cmn::access(p)->ptype() == PT_CBR ) {
//						Packet::del();
//					}
					

				if( HDR_CMN(p)->uid()==2667  ) {
					printf( "节点%d MAC 准备把 uid 为 2667 的packet发送上去RTR\n" , nodeId_);
				}

//					uptarget_->recv( p, (Handler*) 0);
					Scheduler::instance().schedule(uptarget_, p, tx_delay_);
					tx_delay_ += 0.003750000;
					
				}
// new add by qlj 11.14 判断广播信息
			} else if (! burst->error() && ! pdu->error() && 
					pdu->hdr().meshCid().dst() == w_mesh::BROADCAST) {
/*
				W_MeshPdu* pdu_ = new W_MeshPdu (*pdu);
				W_MeshSdu* sdu_ = new W_MeshSdu (*pdu->sdu());  // -> 优先于 *
				sdu_->copyPayload (pdu->sdu());
				pdu_->sdu() = sdu_;
				
				W_MeshSdu* sdu = rreasbuf_->addPdu (pdu_);
*/				// if a full SDU is reassembled, then reschedule it to recvSDU
				
//				W_MeshSdu* sdu = new W_MeshSdu (*pdu->sdu());  // -> 优先于 *
//				sdu->copyPayload (pdu->sdu());
				
//				if ( sdu ) {
					//const double delay = NOW - sdu->timestamp();
		// indicate to the bandwidth manager that we received an SDU
				Packet* p = pdu->sdu()->ip()->copy();
				HDR_CMN(p)->direction () = hdr_cmn::UP;
				//printf("节点%d收到节点%d发来的路由信息\n",nodeId_,
				//		HDR_IP(pdu->sdu()->ip())->src());//调试用的
				//uptarget_->recv(sdu->ip(),(Handler*)0);
				//uptarget_->recv( p, (Handler*) 0);
				//Packet::free(p);

				uptarget_->recv( p, (Handler*) 0);
//				}
			
			} else {
		//		printf("没有处理packet mac： 1683");
				// deallocate the SDU/ns2 packet
//				pdu->sdu()->freePayload ();
//11.4				delete pdu->sdu();
			}

//11.4			delete pdu;
		} // for each PDU of the received burst
	}

	// in any case the burst is deallocated
//11.4	delete burst;
//	burst->free();		// 3.12
}

void
MeshMac::updateH (double& h, double& last)
{
	h = hEstPast_ * h + hEstCurr_ * (NOW - last);
	last = NOW;
}

/*
//void
//MeshMac::setControlChannel (w_mesh::ChannelStatus s)
//{
	if ( W_MeshDebug::trace ("WMAC::setControlChannel" ) ) fprintf (stderr,
			"%.9f WMAC::setCtrlChn [%d] status %s\n",
			NOW, nodeId_,
			(s == w_mesh::TX) ? "TX" : (s == w_mesh::RX) ? "RX" : "NONE");

	phy_[0]->setMode (s, channel_[0]);
}
*/


void
MeshMac::receive (unsigned int channel)
{
	if ( W_MeshDebug::trace ("WMAC::receive" ) ) fprintf (stderr,
			"%.9f WMAC::receive    [%d] chn %d\n",
			NOW, nodeId_, channel);

	//phy_[0]->setMode ( w_mesh::RX, channel_[channel] );
}


void
MeshMac::transmit (unsigned int range, W_MeshNodeId dst, unsigned int channel)
{
	if ( W_MeshDebug::trace ("WMAC::transmit" ) ) fprintf (stderr,
			"%.9f WMAC::transmit   [%d] dst %d range %d chn %d\n",
			NOW, nodeId_, dst, range, channel);

	// dst's index

	int occours = neigh2ndx_.count( dst );
	if ( occours == 0 ) {
		printf ( "目的节点不在邻居列表当中，mac.cc：1665\n" );
		abort();
	}

	const unsigned int ndx = neigh2ndx_[dst];

	// compute the amount of bytes that fit into the range towards dst
	// we account for the physical preamble that must be transmitted
	unsigned int bytes = slots2bytes (ndx, range, true);

	// create a new burst into the fragmentation buffer
	bool room = fragbuf_[ndx]->newBurst (profile_[ndx], bytes);

	// if there is room schedule more PDUs from the scheduler
	if ( room ) scheduler_->schedule (*fragbuf_[ndx], dst);

	// do not send out the buffer is there are not scheduled PDUs within
	if ( fragbuf_[ndx]->getBurst()->npdus() == 0 ) {
		delete fragbuf_[ndx]->getBurst();
		return;
	}

	// if there are backlogged PDUs waiting to be sent to the current
	// neighbor, but there is spare room into the granted set of slots,
	// this means that some capacity could not be used => new backlog
	// should be requested

	const unsigned int spare = 
		( fragbuf_[ndx]->getBurst()->npdus() > 0 )
		? bytes - fragbuf_[ndx]->getBurst()->size()
		: bytes;
	if ( scheduler_->neighbor (ndx) > 0 && spare > 0 )
		bwmanager_->backlog (dst, spare);               // :TODO: check

	// set transmission mode to the given channel
	//phy_[0]->setMode ( w_mesh::TX, channel_[channel] );

	// the backlog must be updated so as to take into account the
	// additional fragmentation overhead of the fragmentation buffer:
	// - each initial fragment incurs an additional overhead equal to
	//   the fragmentation subheader itself
	// - any other fragment adds an additional overhead equal to the
	//   sum of the MAC header + any other subheaders, including fragmentation
	MeshBurst::List& pdus = fragbuf_[ndx]->getBurst()->pdus();
	MeshBurst::List::const_iterator it = pdus.begin();

	// look at the fragmentation subheader (if any) of each PDU
	for ( ; it != pdus.end() ; ++it ) {
		// additional backlog to add, if necessary
		unsigned int backlog = 0;

		// alias to the PDU
		W_MeshPdu* pdu = *it;

		// this is a fragment
		if ( pdu->hdr().fragmentation() ) {
			if ( pdu->fsh().state() == W_MeshFsh::FIRST_FRAG ) // first frag
				backlog = W_MeshFsh::size();
			else                                              // middle/last frag
				backlog = pdu->hdr().size() + W_MeshPdu::meshSubhdrSize() + W_MeshFsh::size();
		}

		// if we encountered a fragment there is something to tell the bwmanager
		if ( backlog ) {
			bwmanager_->backlog (
					(W_MeshNodeId) HDR_IP(pdu->sdu()->ip())->saddr(), // src
					(W_MeshNodeId) HDR_IP(pdu->sdu()->ip())->daddr(), // dst
					pdu->hdr().meshCid().priority(),                 // priority
					pdu->hdr().meshCid().dst(),                      // next-hop
					backlog );                                       // backlog
		}
	}

	// transmit the burst to the PHY (unless it is empty)
	MeshBurst* burst = fragbuf_[ndx]->getBurst();
	if ( burst->npdus() > 0 ) {
		bwmanager_->sent ( dst, burst->size() );

////////////////////////////new add 把burst放进packet，用于跟踪从mac传向phy的data信息
		burst->source() = nodeId_;


		Packet *p = Packet::alloc ();//分配一个空包	
		struct hdr_cmn *hdr=HDR_CMN(p);
		//struct hdr_mac *mac=HDR_MAC(p);
		struct hdr_meshmac *meshmac=HDR_MESHMAC(p);
		//设置普通头部信息
//		hdr->uid()=0;
		hdr->ptype() = PT_MAC_DATA;	//有待添加自己的ptype
		hdr->timestamp()=NOW;
		hdr->size() = burst->size();
		hdr->direction() =hdr_cmn::DOWN;
		meshmac->burst_ = burst;
	
		//计算突发在channel中传输时间
		int burstsize_ = hdr-> size_ ;
		w_mesh::BurstProfile mod = phyMib_->GetModulation ();
		hdr->txtime_ = phyMib_-> GetTrxTime (burstsize_ , mod);	
		burst-> txtime () = hdr->txtime_;







		//printf( " node %d , send a  data burst \n" , nodeId_);
		// new add  跟踪从mac层向phy层发送的burst
		downtarget_->recv(p,(Handler*)0);
		//phy_[0]->sendBurst ( burst );
	}
}

void MeshMac::addNewNode ( W_MeshNodeId nodeID_ ,unsigned int index_ )
{

// mac //! Number of neighbors of this node. unsigned int nneighs_;
// 参考mac的初始化函数 
// 有所vector 容器有待改为map容器!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		//unsigned int i = nneighs_;  // 节点对应index，可看作是linkID
		
		neigh2ndx_[nodeID_] = index_;	
		// 11.11 lhz
		ndx2neigh_[index_] = nodeID_;
		//ndx2neigh_.push_back(nodeID_);
		profile_[index_] = w_mesh::QAM64_3_4;		//初始化为	修改这个值，要跟phy里面一致
		alpha_ [index_] =MeshPhyMib::alpha[w_mesh::QAM64_3_4];
		fragbuf_[index_] = new MeshFragmentationBuffer;
		reasbuf_[index_] = new W_MeshReassemblyBuffer;
		hNeigh_[index_] = 0;
		hNeighLast_[index_] = 0;
		//mshDschLinkQuality_[index_]= *(new LinkQuality);
		class LinkQuality lq_;
		mshDschLinkQuality_[index_]= lq_;

		//updateBurstProfile 会自动添加相应的link	（默认为双向的）			
		macMib_->updateBurstProfile ( nodeId(), nodeID_, 
											w_mesh::QPSK_1_2 );
	

}


void MeshMac::deleteNode ( W_MeshNodeId nodeID_ ,unsigned int index_ )
{

// mac //! Number of neighbors of this node. unsigned int nneighs_;
// 参考mac的addNewNode函数 

		//unsigned int i = nneighs_;  // 节点对应index，可看作是linkID
		
		neigh2ndx_.erase(nodeID_);	
		// 11.11 lhz
		ndx2neigh_.erase(index_);
		profile_.erase(index_);		//初始化为
		alpha_.erase(index_);
		//delete fragbuf_[index_];
		fragbuf_.erase(index_);
		//delete reasbuf_[index_];
		reasbuf_.erase(index_);
		
		hNeigh_.erase(index_);
		hNeighLast_.erase(index_);
		mshDschLinkQuality_.erase(index_);

		//updateBurstProfile 会自动添加相应的link（默认为双向的） 补丁中link的src_ 默认是本节点
		macMib_->deleteBurstProfile ( nodeId(), nodeID_);
		
		unsigned int nb = neigh2ndx_.size();
	

}

void
MeshMac::rtransmit (unsigned int range, W_MeshNodeId dst, unsigned int channel)
{
	if ( W_MeshDebug::trace ("WMAC::transmit" ) ) fprintf (stderr,
			"%.9f WMAC::transmit   [%d] dst %d range %d chn %d\n",
			NOW, nodeId_, dst, range, channel);



	// dst's index
	const unsigned int ndx = dst;

	// compute the amount of bytes that fit into the range towards dst
	// we account for the physical preamble that must be transmitted
	unsigned int bytes = slots2bytes (ndx, range, true);


// 直接把缓存中的pdu添加到burst，不经过分片；
	MeshBurst* burst = new MeshBurst;


	while ( rflow_.size_ > 0 && bytes >0 ) {

		// get the head-of-line PDU
		W_MeshPdu* pdu = rflow_.queue_.front ();

		// otherwise, remove the PDU from queue
		// note that it may happen that this PDU will not be entirely
		// transmitted by the fragmentation buffer. This is not an issue
		// from the point of view of the scheduler, since the MAC is
		// responsible for ensuring that pending fragments are transmitted
		// in order before other PDUs have any chance to interfere
		

//		if ( pdu->size() == bytes ) {
//			printf("pdu 太大了！" ); 
//			delete burst;
//			return;	// 11.17
//		}

		

		bytes -= pdu->size() ;
		if( bytes  > 0 ) {  // 能放下去；
			// update the buffer occupancies
			rflow_.size_ -= pdu->size();          // flow
			rflow_.queue_.pop ();

			// add the PDU to the fragmentation buffer
			burst->addData ( pdu );
		} else {
			 break;
		}
	}

	if (rflow_.size_ < 0 ) {
		rflow_.size_ = 0;
		rflow_.gnt_size_ = 0; 
	}
	if ( burst->npdus() > 0 ) {
		//bwmanager_->sent ( dst, burst->size() );

////////////////////////////new add 把burst放进packet，用于跟踪从mac传向phy的data信息
		Packet *p = Packet::alloc ();//分配一个空包	
		struct hdr_cmn *hdr=HDR_CMN(p);
		//struct hdr_mac *mac=HDR_MAC(p);
		struct hdr_meshmac *meshmac=HDR_MESHMAC(p);
		//设置普通头部信息
//		hdr->uid()=0;

		hdr->ptype() = PT_MAC_DATA;	//有待添加自己的ptype 包含了AODV 和ARP
		hdr->timestamp()=NOW;
		hdr->size() = burst->size();
		hdr->direction() =hdr_cmn::DOWN;
		burst->source() = nodeId_;
		//计算突发在channel中传输时间
		int burstsize_ = hdr-> size_ ;
		w_mesh::BurstProfile mod = phyMib_->GetModulation ();
		hdr->txtime_ = phyMib_-> GetTrxTime (burstsize_ , mod);	
		burst->txtime() = phyMib_-> GetTrxTime (burstsize_ , mod);

		meshmac->burst_ = burst;
  		//printf("节点%d 在mac向下发送路由信息数据 \n",nodeId_);//调试用的
		// new add  跟踪从mac层向phy层发送的burst
		downtarget_->recv(p,(Handler*)0);
		//phy_[0]->sendBurst ( burst );
	} else {
			burst->free();
	}
			
	
}




std::list < unsigned int > &
MeshMac::neighbors ()
{
//	std::list < unsigned int > neighbors_;
	neighbors_.clear();
	std::map<W_MeshNodeId, unsigned int>::iterator it;
	unsigned int num = 0;

	unsigned int nb = neigh2ndx_.size();

	for( it = neigh2ndx_.begin();it !=  neigh2ndx_.end() ; ++it ) {
		
		W_MeshNodeId nd = it->first;
		
		if( it->first != nodeId_ ) {

			neighbors_.push_back ( it->second );
			++num;
		}
		

		if ( it->first == nodeId_ ) {
			printf(  "邻居列表中含有自己\n" );
			abort();
		}
	}

	if ( num != nneighs_ ) {
		printf ( "邻居数据有错 mac.cc：1930" ) ;
		abort();
	}

		

	return neighbors_;
}



//! Return the estimated interval between consecutive opportunities.
double 
MeshMac::h (W_MeshNodeId x) {

	int occours = neigh2ndx_.count( x );
	if ( x == nodeId_ ) {
		return hSelf_;
	} else if ( occours == 1) {
		return hNeigh_[neigh2ndx_[x]];
	} else {  // 不是邻居的节点，则返回一个很大的值
		return 0;
	}

}






















